<?php

class CValidatorManage extends CBase
{
	private static $_validatorList = array();
	
	private static $_currentForm = "";
	
	function __construct(){
		parent::__construct();
	}
	
	public function init($config)
	{
		$formID = $config["formID"];
		
		$validator = false;
		
		if(!key_exists($formID,self::$_validatorList))
		{
			$validator = new CFormValidator();
			
			$validator->initConfig($config);
			
			self::$_validatorList[$formID] = $validator;
		}
		else
		{
			$validator = self::$_validatorList[$formID];
		}
		
		self::$_currentForm = $formID;
		
		return $validator;
	}
	
	private function getFormValidatorCls($formID)
	{
		$formID = $formID?$formID:self::$_currentForm;
		if($formID)
		{
			if(isset(self::$_validatorList[self::$_currentForm]))
			{
				return self::$_validatorList[self::$_currentForm];
			}
		}
		
		CError::handler(E_ERROR,"请先调用init方法",__FILE__,__LINE__);
	}
	
	public function setRules($rules,$formID="")
	{
		$form = $this->getFormValidatorCls($formID);
		
		$form->setRules($rules);
	}
	
	public function getValidatorJs()
	{
		$js = "$(document).ready(function(){";
		foreach (self::$_validatorList as $formID=>$validatorObj)
		{
			$js .= $validatorObj->getFormValidatorJs();
		}
		
		$js .= "});";
		
		return $js;
	}
	
	function getmicrotime()
	{
		list($usec, $sec) = explode(" ",microtime());
		return (((float)$usec + (float)$sec)*1000);
	}
	
	public function getValidatorJsFile()
	{
		$js = $this->getValidatorJs();
		
		if(!$js)
		{
			return "";
		}

		$jsMd5 = md5($js);
		
		$jsExist = false;

		$fHandler = @fopen($this->_basePath."temp".DIRECTORY_SEPARATOR."validator".DIRECTORY_SEPARATOR."jsfile.txt", "a+");
		
		if(!$fHandler)
		{
			CError::handler(E_ERROR,"打开jsfile.txt文件失败!",__FILE__,__LINE__);
		}
		
		$jsList = array();
		
		while (!feof($fHandler)) {
			$content = fgets($fHandler);
			
			$content=str_replace(PHP_EOL,"",$content);
			
			if($content == $jsMd5)
			{
				$jsExist = true;
				break;
			}
		}

		$jsDir = Config::get("formValidator.jsDir");
		if(!$jsDir)
		{
			$jsDir = "js";
		}
		
		$jsDirFull = $this->getAbsolutePath($jsDir);
		
		$jsFile = $jsDirFull."frameworkJs_".$jsMd5.".js";
		
		if(!is_dir($jsDirFull))
		{
			CUtil::createFolder($jsDirFull);
		}
		
		if($jsExist && is_file($jsFile))
		{
			fclose($fHandler);
			return "frameworkJs_".$jsMd5.".js";;
		}
		
		$fp = fopen($jsFile,"w+");
		fwrite($fp,$js);
		fclose($fp);
		
		fwrite($fHandler,$jsMd5.PHP_EOL);
		fclose($fHandler);
		
		return "frameworkJs_".$jsMd5.".js";
		//$this->_renderParam["frameworkJs"] = "<script src='/".$jsDir."frameworkJs.js'></script>";

	}
	
	public function run($formID="")
	{
		$form = $this->getFormValidatorCls($formID);
		
		return $form->run();
	}
	
	/*public function errorInfo()
	{
		if(self::$_validatorList)
		{
			$forms = array_keys(self::$_validatorList);
			
			foreach($forms as $formID)
			{
				$validatorObj = self::$_validatorList[$formID];
				
				//var_dump($validatorObj->_errorList);
			}
		}
	}*/
}


class CFormValidator extends CBase {
	
	private $_rule;
	
	private $_jsStr = "";
	
	//public $_errorList = array();
	
	function __construct() {
	
	}
	
	private $_validatorType = array("FormValidator", "InputValidator","CompareValidator","AjaxValidator","RegexValidator","FunctionValidator","IllegalWordValidator");
	
	/**
	 * 不需要解析到js的属性
	 * @var array
	 */
	private $_settingOther = array("serverValidateClass","serverValidateFun");
	
	public function initConfig($config)
	{
		$alertErrorMsg = isset($config["alertErrorMsg"])?$config["alertErrorMsg"]:true;
		$this->_jsStr = '
			$.formValidator.initConfig({
				formid:"'.$config["formID"].'",';
		
		if(isset($config["validatorgroup"]))
		{
			$this->_jsStr .= "validatorgroup:'".$config["validatorgroup"]."',";
		}
		
		$this->_jsStr .= "onerror:function(msg){
					isValid=false;";
		
		if($alertErrorMsg){
			$this->_jsStr .= 'alert(msg);';
		}
		
		$this->_jsStr .= 'return false;
				},
				onsuccess:function(){
					return true;
				}
			});';
	}
	
	public function setRules($rule)
	{
		if(!is_array($rule))
		{
			return false;
		}
		
		$this->_rule = $rule;
		
		$rulesStr = "";
		
		foreach($rule as $controlId=>$ruleItem)
		{
			$rulesStr .= "$(\"#".$controlId."\")";
			foreach ($ruleItem as $validatorType=>$validatorItem)
			{
				if(!in_array(ucwords($validatorType),$this->_validatorType))
				{
					continue;
				}
				$rulesStr .= ".".$validatorType."({";
				$validatorItemLength = count($validatorItem);
				//$i = 1;
				foreach($validatorItem as $settingItem=>$settingValue)
				{
					if(in_array($settingItem,$this->_settingOther))
					{
						continue;
					}
					
					if(is_array($settingValue) && ($itemCount=count($settingValue))>0)
					{
						$j=1;
						
						$rulesStr .= "\"".$settingItem."\"".":{";
						foreach ($settingValue as $itemKey=>$itemValue)
						{
							if($itemValue!="true" && $itemValue!="false" && $itemValue!="null")
							{
								$itemValue = "\"".$itemValue."\"";
							}
							
							if($j<$itemCount)
							{
								$rulesStr .= "\"".$itemKey."\"".":".$itemValue.",";
							}
							else
							{
								$rulesStr .= "\"".$itemKey."\"".":".$itemValue;
							}
							
							$j++;
						}
						
						$rulesStr .= "},";
					}
					else
					{
						if("regexp" == $settingItem)
						{
							$settingValue = preg_replace('/([^\\\\].)?(\\\\)([^\\\\].)/', "$1\\\\\\\\$3",$settingValue);
						}
						if($settingValue!="true" && $settingValue!="false" && $settingValue!="null" && substr(trim($settingValue),0,8)!="function" && $settingItem!="fun")
						{
							$settingValue = "\"".$settingValue."\"";
						}

						$rulesStr .= "\"".$settingItem."\"".":".$settingValue.",";
					}
				}
				
				if(substr($rulesStr,-1,1)==",")
				{
					$rulesStr = substr($rulesStr,0,strlen($rulesStr)-1);
				}

				$rulesStr .= "})";
			}
			
			$rulesStr .= ";";
		}
		
		$this->_jsStr .= $rulesStr;
	}
	
	public function getFormValidatorJs()
	{
		return $this->_jsStr;
	}
	
	private function getPostValue($key)
	{
		if(isset($_POST) && isset($_POST[$key]))
		{
			return $_POST[$key];
		}
		return false;
	}
	
	public function run()
	{
		$controlValue = "";
		
		$error = false;
		$errorList = array();
		
		foreach($this->_rule as $controlId=>$ruleItem)
		{
			$controlValue = $this->getPostValue($controlId);
			$empty = false;
			foreach ($ruleItem as $validatorType=>$validatorItem)
			{
				if(!in_array(ucwords($validatorType),$this->_validatorType))
				{
					continue;
				}
				
				if("formValidator"==$validatorType)
				{
					$empty = isset($validatorItem["empty"])?$validatorItem["empty"]:false;
					continue;
				}

				if($empty==true && $controlValue=="")
				{
					$error = true;
				}
				else{
					$error = $this->$validatorType($validatorItem,$controlValue);
				}
				if($error!==true)
				{
					if(!key_exists($controlId,$errorList))
					{
						$errorList[$controlId] = $error;
					}
					
				}
			}
		}
		
		//$this->_errorList = $errorList;
		
		return $errorList;
	}
	
	private function formValidator($c,$controlValue)
	{
		$setting = array(
			"validatorgroup"=>"1",
		    "empty"=>"false",
		    "submitonce"=>"false",
		    "automodify"=>"false",
		    "onshow"=>"请输入内容",
		    "onfocus"=>"请输入内容",
		    "oncorrect"=>"输入正确",
		    "onempty"=>"输入内容为空",
		    "defaultvalue"=>"null",
		    "bind"=>"true",
		    "validatetype"=>"InitValidator",
		    "tipcss"=>array(
		    	"left"=>"10px",
			    "top"=>"1px",
			    "height"=>"20px",
			    "width"=>"250px"
			),
		    "triggerevent"=>"blur",
		    "forcevalid"=>"false"
		);
		
		$setting = $c+$setting;
		
		if(!$setting["bind"])
		{
			return true;
		}
		
		if($setting["empty"]=="true")
		{
			return true;
		}
		
		if($controlValue)
		{
			return true;
		}
		
		return $setting["onempty"];
	}
	
	private function inputValidator($c,$controlValue)
	{
		
		$setting = array(
			"isvalid"=>"false",
	    	"min"=>"0",
	   		"max"=>"99999999999999",
	    	"type"=>"size",
	    	"onerror"=>"输入错误",
	    	"validatetype"=>"InputValidator",
	    	"empty"=>array(
	    		"leftempty"=>"true",
				"rightempty"=>"true",
				"emptyerror"=>"null"
			),
	    	"wideword"=>"true"
	    );
	   
	    //$setting = array_merge($setting,$c);
	    
	    CUtil::array_merge_extend($setting, $c);
	    
	    $emptyError = "";

	    
	    if(is_string($controlValue))
	    {
		    if($setting["empty"]["leftempty"]=="false")
		    {
		    	if(strlen($controlValue)!=strlen(ltrim($controlValue)))
		    	{
		    		$emptyError = $setting["empty"]["emptyerror"];
		    	}
		    }
		    
		    if(!$emptyError)
		    {
			    if($setting["empty"]["rightempty"]=="false")
			    {
			    	if(strlen($controlValue)!=strlen(rtrim($controlValue)))
			    	{
			    		$emptyError = $setting["empty"]["emptyerror"];
			    	}
			    }
		    }
	    }

	    if($emptyError)
	    {
	    	return $emptyError;
	    }
	    
	    $vLen = is_string($controlValue)?mb_strlen($controlValue,"utf-8"):(is_array($controlValue)?count($controlValue):0);
	    $val = "";
	 	$type = $setting["type"];
	 	$lb_go_on = false;
	 	
	 	if ($type == "size")
	 	{
			if(!$emptyError)
			{
				$lb_go_on = true;
			}
			
			if ($lb_go_on) {
				$val = $vLen; 
			}
		}
		else if ($type == "date" || $type == "datetime")
		{
			$lb_go_on = CUtil::isDate($controlValue);

			if($lb_go_on){
				$val = strtotime($controlValue);
				$setting["min"] = strtotime($setting["min"]);
				$setting["max"] = strtotime($setting["max"]);
            }
		}
		else {
			if (is_int($setting["min"]))
			{
				$val = $setting["min"];
                $lb_go_on = true;
			}
			
			if (is_string($setting["min"]))
			{
				$lb_go_on = true;
			}
		}

		$errormsg = "";
		$isValid = false;

		if ($lb_go_on)
		{
			if ($val < $setting["min"])
			{
				if(isset($setting["onerrormin"]))
				{
					$errormsg = $setting["onerrormin"];
				}
				else
				{
					$errormsg = $setting["onerror"];
				}
			}
			else if ($val > $setting["max"])
			{
				if(isset($setting["onerrormax"]))
				{
					$errormsg = $setting["onerrormax"];
				}
				else
				{
					$errormsg = $setting["onerror"];
				}
			}
			else
			{
				$isValid = true;
			}
		}

		if($isValid)
		{
			return true;
		}
		
		return $errormsg?$errormsg:$setting["onerror"];
	}
	
	private function compareValidator($c,$controlValue)
	{
		$setting = array(
			"isvalid"=>"false",
			"desid"=>"",
			"datatype"=>"string",
			"operateor"=>"=",
			"onerror"=>"输入错误",
			"validatetype"=>"CompareValidator"
		);
		
		$setting = array_merge($setting,$c);
		
		$desValue = $this->getPostValue($setting["desid"]);
		
		if($setting["datatype"]=="date" || $setting["datatype"]=="datetime")
		{
			if(CUtil::isDate($controlValue)==false || CUtil::isDate($desValue) ==false)
			{
				return $setting["onerror"];
			}
			
			$controlValue = strtotime($controlValue);
			$desValue = strtotime($desValue);
		}
		
		$isValid = false;
		
	 	switch ($setting["operateor"]) {
            case "=":
                if ($controlValue == $desValue) {
                	$isValid = true; 
                }
                break;
            case "!=":
                if ($controlValue != $desValue) {
                	$isValid = true; 
                }
                break;
            case ">":
                if ($controlValue > $desValue) {
                	$isValid = true; 
                }
                break;
            case ">=":
                if ($controlValue >= $desValue) {
                	$isValid = true;
                }
                break;
            case "<":
                if ($controlValue < $desValue) {
                	$isValid = true; 
                }
                break;
            case "<=":
                if ($controlValue <= $desValue) {
                	$isValid = true;
                }
                break;
        }
        
        if (!$isValid)
        {
        	return $setting["onerror"];
        }
        
        return true;
	}
	
	private function ajaxValidator($c,$controlValue)
	{
		$setting = array(
			"isvalid"=>"false",
			"lastValid"=>"",
			"type"=>"GET",
			"url"=>"",
			"addidvalue"=>"true",
			"datatype"=>"html",
			"data"=>"",
			"async"=>"true",
			"cache"=>"false",
			"beforesend"=>"function() { return true; }",
			"success"=>"function() { return true; }",
			"complete"=>"function() { }",
			"processdata"=>"false",
			"error"=>"function() { }",
			"buttons"=>"null",
			"onerror"=>"服务器校验没有通过",
			"onwait"=>"正在等待服务器返回数据",
			"validatetype"=>"AjaxValidator",
			"serverValidateClass"=>"",
			"serverValidateFun"=>"",
		);
		
		$isValid = false;
		
		$setting = array_merge($setting,$c);
		
		$serverValidateClass = $setting["serverValidateClass"];
		$serverValidateFun = $setting["serverValidateFun"];
		
		if($serverValidateClass && $serverValidateFun)
		{
			if(class_exists($serverValidateClass))
			{
				$vCls = new $serverValidateClass();
				if(method_exists($vCls, $serverValidateFun))
				{
					$isValid = $vCls->$serverValidateFun($controlValue);
				}
			}
		}
		else
		{
			return true;
		}
		
		if(!$isValid)
		{
			return $setting["onerror"];
		}
		
		return true;
	}
	
	private function regexValidator($c,$controlValue)
	{
		$setting = array(
			"isvalid"=>"false",
			"regexp"=>"",
			"param"=>"i",
			"datatype"=>"string",
			"onerror"=>"输入的格式不正确",
			"validatetype"=>"RegexValidator"
		);
		
		$setting = array_merge($setting,$c);
		
		$regexEnum = array(
			"intege"=>"^-?[1-9]\\d*$",					//整数
			"intege1"=>"^[1-9]\\d*$",					//正整数
			"intege2"=>"^-[1-9]\\d*$",					//负整数
			"num"=>"^([+-]?)\\d*\\.?\\d+$",			//数字
			"num1"=>"^[1-9]\\d*|0$",					//正数（正整数 + 0）
			"num2"=>"^-[1-9]\\d*|0$",					//负数（负整数 + 0）
			"decmal"=>"^([+-]?)\\d*\\.\\d+$",			//浮点数
			"decmal1"=>"^[1-9]\\d*.\\d*|0.\\d*[1-9]\\d*$",//正浮点数
			"decmal2"=>"^-([1-9]\\d*.\\d*|0.\\d*[1-9]\\d*)$", //负浮点数
			"decmal3"=>"^-?([1-9]\\d*.\\d*|0.\\d*[1-9]\\d*|0?.0+|0)$", //浮点数
			"decmal4"=>"^[1-9]\\d*.\\d*|0.\\d*[1-9]\\d*|0?.0+|0$", //非负浮点数（正浮点数 + 0）
			"decmal5"=>"^(-([1-9]\\d*.\\d*|0.\\d*[1-9]\\d*))|0?.0+|0$", //非正浮点数(负浮点数 + 0)
			"email"=>"^\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]+$", //邮件
			"color"=>"^[a-fA-F0-9]{6}$",				//颜色
			"url"=>"^http[s]?:\\/\\/([\\w-]+\\.)+[\\w-]+([\\w-./?%&=]*)?$",	//url
			"chinese"=>"^[\\u4E00-\\u9FA5\\uF900-\\uFA2D]+$",					//仅中文
			"ascii"=>"^[\\x00-\\xFF]+$",				//仅ACSII字符
			"zipcode"=>"^\\d{6}$",						//邮编
			"mobile"=>"^(13|15)[0-9]{9}$",				//手机
			"ip4"=>"^(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)$",	//ip地址
			"notempty"=>"^\\S+$",						//非空
			"picture"=>"(.*)\\.(jpg|bmp|gif|ico|pcx|jpeg|tif|png|raw|tga)$",	//图片
			"rar"=>"(.*)\\.(rar|zip|7zip|tgz)$",								//压缩文件
			"date"=>"^\\d{4}(\\-|\\/|\\.)\\d{1,2}\\1\\d{1,2}$",					//日期
			"qq"=>"^[1-9]*[1-9][0-9]*$",				//QQ号码
			"tel"=>"^(([0\\+]\\d{2,3}-)?(0\\d{2,3})-)?(\\d{7,8})(-(\\d{3,}))?$",	//电话号码的函数(包括验证国内区号,国际区号,分机号)
			"username"=>"^\\w+$",						//用来用户注册。匹配由数字、26个英文字母或者下划线组成的字符串
			"letter"=>"^[A-Za-z]+$",					//字母
			"letter_u"=>"^[A-Z]+$",					//大写字母
			"letter_l"=>"^[a-z]+$",					//小写字母
			"idcard"=>"^[1-9]([0-9]{14}|[0-9]{17})$"	//身份证
		);
		
		$datatype = $setting['datatype'];

		$regex = $setting["regexp"];
		
		if($datatype=="enum")
		{
			if(key_exists($regex, $regexEnum))
			{
				$regex = $regexEnum[$regex];
			}
			else
			{
				$regex = "";
			}
		}
		if(!$regex)
		{
			return true;
		}
		
		$matchCount = preg_match("/".$regex."/",$controlValue);

		if($matchCount)
		{
			return true;
		}
		
		return $setting["onerror"];
	}
	
	private function functionValidator($c,$controlValue)
	{
		$setting = array(
			"isvalid"=>"true",
			"fun"=>"function() { this.isvalid = true; }",
			"validatetype"=>"FunctionValidator",
			"onerror"=>"输入错误",
			"serverValidateClass"=>"",
			"serverValidateFun"=>"",
		);
		
		$setting = array_merge($setting,$c);
		
		$isValid = false;
		
		$serverValidateClass = $setting["serverValidateClass"];
		$serverValidateFun = $setting["serverValidateFun"];
		
		if($serverValidateClass && $serverValidateFun)
		{
			if(class_exists($serverValidateClass))
			{
				$vCls = new $serverValidateClass();
				if(method_exists($vCls, $serverValidateFun))
				{
					$isValid = $vCls->$serverValidateFun($controlValue);
				}
			}
		}
		else
		{
			return true;
		}
		
		if(!$isValid)
		{
			return $setting["onerror"];
		}
		
		return true;
	}
}

?>